/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.bemanager.service;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.bef.bemanager.befexception.BeManagerException;
import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.json.element.BizElementDeserializer;
import com.inspur.edp.bef.bizentity.json.element.BizElementSerializer;
import com.inspur.edp.bef.bizentity.util.UpdateBeElementUtil;
import com.inspur.edp.bef.bizentity.util.UpdateBeVariableUtil;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.json.Variable.CommonVariableDeserializer;
import com.inspur.edp.cef.designtime.api.json.Variable.CommonVariableSerializer;
import com.inspur.edp.cef.designtime.api.variable.CommonVariable;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import lombok.var;
import org.springframework.util.StringUtils;

/**
 * 更新字段信息服务
 *
 * @author haoxiaofei
 */
public class UpdateElementCollectionService {

  private final java.util.HashMap<String, GspMetadata> metadataDic = new java.util.HashMap<String, GspMetadata>();
  private MetadataService lcmDtService;

  private MetadataService getLcmDtService() {
    if (lcmDtService == null) {
      lcmDtService = SpringBeanUtils.getBean(MetadataService.class);
    }
    return lcmDtService;

  }

  private static final String ERRORCODE = "UpdateElementService";


  public static UpdateElementCollectionService getInstance() {
    return new UpdateElementCollectionService();
  }

  ///#region 批量更新

  /**
   * 批量更新udt字段
   *
   * @param elements 字段集合
   */
  public void handleUdtElements(String path, java.util.ArrayList<IGspCommonElement> elements) {
    if (elements == null || elements.isEmpty()) {
      return;
    }
    for (IGspCommonElement ele : elements) {
      if (!ele.getIsUdt()) {
        continue;
      }
      GspMetadata refUdtMetadata = getRefMetadata(path, ele.getUdtID(), "UDT");
      UpdateBeElementUtil util = new UpdateBeElementUtil();
      util.updateElementWithRefUdt((GspBizEntityElement) ele,
          (UnifiedDataTypeDef) refUdtMetadata.getContent(), false);
    }
  }

  /**
   * 批量更新关联字段
   *
   * @param elements 字段集合
   */
  public void handleRefElements(String path, java.util.ArrayList<IGspCommonElement> elements) {
    if (elements == null || elements.isEmpty()) {
      return;
    }
    for (IGspCommonElement element : elements) {
      if (!element.getHasAssociation()) {
        continue;
      }
      for (GspAssociation asso : element.getChildAssociations()) {
        setAssoModelInfo(path, asso);
      }
    }
  }

  /**
   * 根据选中的udt元数据,更新多值udt字段信息 更新ChildElements,Mapping 说明：若为字段上选择udt，所有属性带出；若为加载更新，则仅更新使用方式为【约束】的属性。
   *
   * @return 更新后字段的json序列化
   */
  public String updateElementWithRefUdt(String refUdtId, String path, String udtElementJson,
      boolean isFirstChoose) {
    GspMetadata refUdtMetadata = getRefMetadata(path, refUdtId, "UDT");
    Object tempVar;
    ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();

    module.addDeserializer(IGspCommonField.class, new BizElementDeserializer());
    module.addSerializer(IGspCommonField.class, new BizElementSerializer());
    mapper.registerModule(module);
    try {
      tempVar = mapper.readValue(udtElementJson, GspBizEntityElement.class);

    } catch (JsonProcessingException e) {
      throw new RuntimeException("字段反序列化失败！");
    }

    var element = (GspBizEntityElement) ((tempVar instanceof GspBizEntityElement) ? tempVar : null);
    IMetadataContent content = refUdtMetadata.getContent();
    if (content instanceof UnifiedDataTypeDef) {
      UpdateBeElementUtil util = new UpdateBeElementUtil();
      util.updateElementWithRefUdt(element, (UnifiedDataTypeDef) content, isFirstChoose);
    } else {
      throw new BeManagerException("", ERRORCODE, "未定义的业务字段元数据类型。", null, ExceptionLevel.Error,
          false);
    }

    String eleJson = null;
    try {
      eleJson = mapper.writeValueAsString(tempVar);
    } catch (JsonProcessingException e) {
      throw new RuntimeException("字段序列化失败！");
    }
    return eleJson;
  }

  /**
   * 更新关联UDT虚拟字段
   *
   * @param refUdtId 关联UDT ID
   * @param path 路径
   * @param udtElementJson UDT字段信息
   * @param isFirstChoose
   * @return 序列化至
   */
  public String updateVariableWithRefUdt(String refUdtId, String path, String udtElementJson,
      boolean isFirstChoose) {
    GspMetadata refUdtMetadata = getRefMetadata(path, refUdtId, "UDT");
    ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    module.addDeserializer(IGspCommonField.class, new CommonVariableDeserializer());
    module.addSerializer(IGspCommonField.class, new CommonVariableSerializer());
    mapper.registerModule(module);
    Object tempVar2;
    try {
      tempVar2 = mapper.readValue(udtElementJson, IGspCommonField.class);
    } catch (JsonProcessingException e) {
      throw new RuntimeException("变量字段反序列化失败！");
    }

    var element = (CommonVariable) ((tempVar2 instanceof CommonVariable) ? tempVar2 : null);
    IMetadataContent content = refUdtMetadata.getContent();
    if (content instanceof UnifiedDataTypeDef) {
      UpdateBeVariableUtil util = new UpdateBeVariableUtil();
      util.updateElementWithRefUdt(element, (UnifiedDataTypeDef) content, isFirstChoose);
    } else {
      throw new BeManagerException("", ERRORCODE, "未定义的业务字段元数据类型。", null, ExceptionLevel.Error,
          false);
    }

    String eleJson = null;
    try {
      eleJson = mapper.writeValueAsString(element);
    } catch (JsonProcessingException e) {
      throw new RuntimeException("变量字段序列化失败！");
    }
    return eleJson;
  }

  ///#endregion

  ///#region 选择关联时处理

  /**
   * 若关联为选择udt带出，则带出字段标签="{当前字段标签}_{udt带出字段标签}"
   *
   * @param element
   */
  public void updateFieldWithAsso(String path, IGspCommonField element) {
    if (!element.getHasAssociation()) {
      return;
    }
    for (GspAssociation asso : element.getChildAssociations()) {
      setAssoModelInfo(path, asso);
      handleUdtRefField(asso, element.getLabelID());
    }
  }

  ///#endregion

  ///#endregion

  ///#region 私有方法

  /**
   * udt关联带出字段，标签需处理
   *
   * @param asso
   * @param prefix
   */
  private void handleUdtRefField(GspAssociation asso, String prefix) {

    for (var refEle : asso.getRefElementCollection()) {
      if (!refEle.getIsUdt()) {
        continue;
      }

      for (var childEle : refEle.getChildElements()) {
        childEle.setLabelID(String.format(prefix, "_", childEle.getLabelID()));
      }
    }
  }

  /**
   * 赋值AssoModelInfo 1.首次选择关联时调用赋值； 2.打开设计器时需调用更新；
   *
   * @param asso
   */
  private void setAssoModelInfo(String path, GspAssociation asso) {

    GspBusinessEntity refModel = (getRefMetadata(path, asso.getRefModelID(), "BE").getContent() instanceof GspBusinessEntity)
        ? getRefMetadata(path, asso.getRefModelID(), "BE").getContent() : null;
    asso.getAssoModelInfo().setMainObjCode(refModel.getMainObject().getCode());
    asso.getAssoModelInfo().setModelConfigId(refModel.getDotnetGeneratedConfigID());
  }

  private GspMetadata getRefMetadata(String path, String id, String metadataType) {
    if (metadataDic.containsKey(id)) {
      return metadataDic.get(id);
    }
    GspMetadata metadata = StringUtils.isEmpty(path)
        ? SpringBeanUtils.getBean(RefCommonService.class).getRefMetadata(id)
        : getLcmDtService().getRefMetadata(path, id);
    if (metadata.getContent() == null) {
      throw new RuntimeException(
          "使用IRefCommonService服务获取元数据失败，元数据Id=" + id + (metadataType.length() > 0 ? ("，元数据类型"
              + metadataType) : ""));
    }
    metadataDic.put(id, metadata);
    return metadata;
  }

  ///#endregion
}
